--------------------------------------------------------------------------------
-- This package is a Quaternion's generic package....
--
-- Copyright (C) 2011 Vincent DIEMUNSCH.
-- GNU General Public License.
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any later
-- version.
--
-- This file is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- this program.  If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------

with Ada.Numerics.Generic_Complex_Types,
     Ada.Numerics.Generic_Real_Arrays;

generic
   type Real is digits <>;
   with package Real_Arrays   is new Ada.Numerics.Generic_Real_Arrays   (Real);
   with package Complex_Types is new Ada.Numerics.Generic_Complex_Types (Real);
   use Complex_Types;

package Generic_Quaternion_Types is
   pragma Pure (Generic_Quaternion_Types);

   subtype Vector is Real_Arrays.Real_Vector(1..3);
   use type Vector;

   ----------------
   -- Quaternion --
   ----------------

   type Quaternion is record
      Re : Real'Base;
      Im : Vector;
   end record;

   type Pure_Imaginary is private;
   pragma Preelaborable_Initialization (Pure_Imaginary);

   i : constant Pure_Imaginary;
   j : constant Pure_Imaginary;
   k : constant Pure_Imaginary;

   function Re (X : Quaternion)      return Real'Base is (X.Re);
   function Im (X : Quaternion)      return Vector    is (X.Im);
   function Im (X : Pure_Imaginary)  return Vector;
   function Scalar_Part (X : Quaternion) return Real'Base renames Re;
   function Vector_Part (X : Quaternion) return Vector    renames Im;


   procedure Set_Re (X : in out Quaternion;     Re : Real'Base);
--   procedure Set_Im (X : in out Quaternion;     Im : Vector);
--   procedure Set_Im (X :    out Pure_Imaginary; Im : Vector);

--   function Compose_From_Cartesian (Re, Im_i, Im_j, Im_k : Real'Base)
--                                    return Quaternion;
--   function Compose_From_Cartesian (Re : Real'Base; im : Pure_Imaginary)
--                                    return Quaternion;
--   function Compose_From_Cartesian (Re     : Real'Base)      return Quaternion;
--   function Compose_From_Cartesian (Im     : Vector) return Quaternion;

   function "+"       (Right : Quaternion) return Quaternion;
   function "-"       (Right : Quaternion) return Quaternion;
   function Conjugate (X     : Quaternion) return Quaternion;
   function Inv       (X     : Quaternion) return Quaternion;

   function "+" (Left, Right : Quaternion) return Quaternion;
   function "-" (Left, Right : Quaternion) return Quaternion;
   function "*" (Left, Right : Quaternion) return Quaternion;
   -- Warning product of Quaternions is not commutative ie : Q1 * Q2 /= Q2 * Q1
   function "/" (Left, Right : Quaternion) return Quaternion is (Left * inv(Right));
   -- function "\" (Left, Right : Quaternion) return Quaternion is (inv(Left) * Right);

   function "+" (Left : Real'Base;  Right : Pure_Imaginary) return Quaternion;
   function "+" (Left : Quaternion; Right : Pure_Imaginary) return Quaternion;
   function "*" (Left : Real'Base;  Right : Pure_Imaginary) return Pure_Imaginary;

   function "**"(Left : Quaternion; Right : Natural) return Quaternion;

   function "+" (Left : Real'Base;  Right : Quaternion) return Quaternion;
   function "+" (Left : Quaternion; Right : Real'Base)  return Quaternion;
   function "*" (Left : Real'Base;  Right : Quaternion) return Quaternion;
   function "*" (Left : Quaternion; Right : Real'Base)  return Quaternion;
   function "/" (Left : Quaternion; Right : Real'Base)  return Quaternion;

   function "+" (Left : Complex;    Right : Quaternion) return Quaternion;
   function "+" (Left : Quaternion; Right : Complex)    return Quaternion;
   function "*" (Left : Complex;    Right : Quaternion) return Quaternion;
   function "*" (Left : Quaternion; Right : Complex)    return Quaternion;
   function "/" (Left : Quaternion; Right : Complex)    return Quaternion;

   function Modulus  (X     : Quaternion) return Real'Base; -- Norm
   function "abs"    (Right : Quaternion) return Real'Base renames Modulus;
   function Versor   (X     : Quaternion) return Quaternion is (X / Modulus(X));
   function Argument (X     : Quaternion) return Real'Base;
--   function Argument (X     : Quaternion;
--                      Cycle : Real'Base)  return Real'Base;
   function Unit_Vector (X  : Quaternion) return Pure_Imaginary;

--   function Compose_From_Polar (Norm, Argument : Real'Base;
--                                Unit_Vector    : Pure_Imaginary)
--      return Quaternion;
--   function Compose_From_Polar (Modulus, Argument, Cycle : Real'Base;
--                                Unit_Vector    : Pure_Imaginary)
--      return Quaternion;

--   function Compose_From_Complex (z1, z2 : Complex) return Quaternion;


   function Image (left : Complex)    return String;
   function Image (Left : Quaternion) return String;

private

   type Pure_Imaginary is new Vector;

   i : constant Pure_Imaginary := (1.0, 0.0, 0.0);
   j : constant Pure_Imaginary := (0.0, 1.0, 0.0);
   k : constant Pure_Imaginary := (0.0, 0.0, 1.0);

end Generic_Quaternion_Types;
